/**
 * Copyright (C), 2015-2018
 * FileName: FilterConfiguration
 * Author:   Dayu Hou
 * Date:     2018/1/10 11:38
 * Description:
 * History:
 * <author>          <time>         <desc>
 */
package com.apache.log.common;

import com.apache.cache.service.impl.redis.RedisCoreFactory;
import com.apache.database.constant.SpringContextLoader;
import com.apache.log.db.DbBaseDao;
import com.apache.log.db.impl.DefDbDaoImpl;
import com.apache.log.es.ESBaseDao;
import com.apache.log.es.config.IndexConfig;
import com.apache.log.es.impl.DefEsDaoImpl;
import com.apache.log.manager.LogManager;
import com.apache.log.service.impl.DBManagerImpl;
import com.apache.log.service.impl.ESManagerImpl;
import com.apache.rpc.StartSocketPortListener;
import com.apache.rpc.common.RpcUtil;
import com.apache.tools.DateUtils;
import com.apache.tools.StrUtil;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ajp.AjpNioProtocol;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.http.LegacyCookieProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import redis.clients.jedis.JedisPool;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Dayu Hou
 * @since 1.0.0
 */
@Configuration
public class FilterConfiguration extends WebMvcConfigurerAdapter {

    @Autowired
    private Environment env;

    @Bean
    public SpringContextLoader springContextLoader(){
        return new SpringContextLoader();
    }
    /**
     * 加载listener
     */
    @Bean
    public StartSocketPortListener startSocketPortListener() {
        String socketPort = StrUtil.doNull(env.getProperty("rpc.service.port"), "20808");
        StartSocketPortListener listener = new StartSocketPortListener(socketPort);
        if (StrUtil.isNotNull(env.getProperty("rpc.version"))) {
            RpcUtil.getInstance().setVersion(env.getProperty("rpc.version"));
        }
        listener.registry();
        return listener;
    }

    @Bean
    public FilterRegistrationBean encodingFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CharacterEncodingFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter("encoding", "UTF-8");
        registration.addInitParameter("forceEncoding", "true");
        registration.setName("encodingFilter");
        registration.setOrder(1);
        return registration;
    }

    @Bean("jedisPool")
    public JedisPool initJedisPool() {
        Map<String, String> constant = new HashMap<String, String>();
        constant.put("redis_master_ip",StrUtil.doNull(env.getProperty("spring.redis.host"),"localhost"));
        constant.put("redis_master_port",env.getProperty("spring.redis.port"));
        constant.put("redis_auth",StrUtil.doNull(env.getProperty("spring.redis.password"),"14YVeC0PToxRIAs"));
        constant.put("redis_maxActive",env.getProperty("spring.redis.jedis.pool.max-active"));
        constant.put("redis_maxIdle",env.getProperty("spring.redis.jedis.pool.max-idle"));
        constant.put("redis_maxWait",env.getProperty("spring.redis.jedis.pool.max-wait"));
        RedisCoreFactory.getInstance().setConstant(constant);
        return RedisCoreFactory.getInstance().getJedisPool();
    }
    /**
     * 自定义tomcat初始化工厂
     */
    @Bean
    public TomcatServletWebServerFactory createEmbeddedServletContainerFactory() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.setUriEncoding(Charset.forName("UTF-8"));
        tomcat.setPort(Integer.parseInt(doNull(env.getProperty("spring.tomcat.port"), "8080")));
        tomcat.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        if (StrUtil.isNotNull(env.getProperty("spring.tomcat.ajp.port"))) {
            tomcat.addAdditionalTomcatConnectors(createAjpConnector());//createSslConnector(),
        }
        PropertiesConfig.setApplicatinConfig(env);
        return tomcat;
    }

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
        return (factory) -> factory.addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
    }

    @Bean("logManager")
    public LogManager logManager(){
        String useDataType = env.getProperty("use.data.type");//数据存储类型(ES,DB)
        LogManager logManager = null;
        if("ES".equalsIgnoreCase(useDataType)){
            ESBaseDao dao = new DefEsDaoImpl(env.getProperty("jest.host"));
            IndexConfig indexConfig = new IndexConfig();
            if(!dao.indexExists(PropertiesConfig.MODEL_INDEX)){
                dao.createIndex(PropertiesConfig.MODEL_INDEX,"doc",indexConfig.getSettings(""),indexConfig.getMappings(PropertiesConfig.MODEL_INDEX));
            }
            if(!dao.indexExists(PropertiesConfig.MODEL_DETAIL_INDEX)){
                dao.createIndex(PropertiesConfig.MODEL_DETAIL_INDEX,"doc",indexConfig.getSettings(""),indexConfig.getMappings(PropertiesConfig.MODEL_DETAIL_INDEX));
            }
            String indexName = PropertiesConfig.OPERATION_INDEX+"-"+ DateUtils.Now.fmt_yyyy();
            if(!dao.indexExists(indexName)){
                dao.createIndex(indexName,"doc",indexConfig.getSettings(PropertiesConfig.OPERATION_INDEX),indexConfig.getMappings(PropertiesConfig.OPERATION_INDEX));
            }
            logManager = new ESManagerImpl(dao);
        } else {
            DbBaseDao dao = new DefDbDaoImpl(env.getProperty("datasourceKey"));
            logManager = new DBManagerImpl(dao);
        }
        return logManager;
    }

    /**
     * ajp配置
     */
    private Connector createAjpConnector() {
        Connector connector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
        AjpNioProtocol protocol = (AjpNioProtocol) connector.getProtocolHandler();
        connector.setScheme("http");
        protocol.setSecretRequired(false);
        connector.setPort(Integer.parseInt(doNull(env.getProperty("spring.tomcat.ajp.port"), "8009")));
        protocol.setPacketSize(Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxHttpHeaderSize"), "28192")));
        setHttpParams(protocol);
        return connector;
    }

    /**
     * 设置优化参数
     */
    private void setHttpParams(AbstractProtocol protocol) {
        //在任何给定的时间内，服务器将接受和处理的最大连接数
        protocol.setMaxConnections(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxConnections"), "10000")));
        //设置最大线程数，如果未配置默认值为200
        protocol.setMaxThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxThreads"), "200")));
        //minSpareThreads：线程的最小运行数目，这些始终保持运行。如果未指定，默认值为10
        protocol.setMinSpareThreads(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.minSpareThreads"), "10")));
        //当请求已经被接受，但未被处理，也就是等待中的超时时间。单位为毫秒，默认值为60000
        protocol.setConnectionTimeout(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.timeOut"), "60000")));
        //当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度，默认值为100
        protocol.setAcceptCount(
                Integer.parseInt(doNull(env.getProperty("spring.tomcat.acceptCount"), "200")));
    }

    private String doNull(String str, String defaultStr) {
        if (isNull(str)) {
            return defaultStr;
        }
        return str;
    }

    private boolean isNull(String str) {
        boolean mark = false;
        if (null == str || str.trim().equals("") || str.trim().equalsIgnoreCase("null")) {
            mark = true;
        }
        return mark;
    }

    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {

        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setMaxHttpHeaderSize(Integer.parseInt(doNull(env.getProperty("spring.tomcat.maxHttpHeaderSize"), "28192")));
            setHttpParams(protocol);
        }
    }
}